// included in Array.h

template<class T>
const int Array<T>::DefaultCapacity = 10;

template<class T>
Array<T>::Array( void ):capacity_( DefaultCapacity ),size_(0),pData_(0)
{
	pData_ = new T[capacity_];
}

template<class T>
Array<T>::Array( const int& capacity ):capacity_(capacity),size_(0),pData_(0)
{
	pData_ = new T[capacity_];
}

template<class T>
Array<T>& Array<T>::operator = ( const Array<T>& rsh)
{
	if(this == &rsh)
	{
		return *this;
	}
	SAFE_DELETE_ARRAY(pData_);
	this->size_     = rsh.size_;
	this->capacity_ = rsh.capacity_;
	pData_    = new T[capacity_];
	memcpy_s(pData_, capacity_*sizeof(T), rsh.pData_, size_*sizeof(T));
	return *this;
}

template<class T>
Array<T>::Array(const Array<T>& copyFrom)
{
	pData_ = 0;
	*this = copyFrom;
}

template<class T>
T& Array<T>::operator[]( const int& index )
{
	assert( index >= 0 && index < capacity_ );
	return pData_[index];
}


template<class T>
Array<T>::~Array( void )
{
	if(pData_)
		delete[] pData_;
}

template<class T>
int Array<T>::Capacity( void ) const
{
	return capacity_;
}

template<class T>
void Array<T>::SetCapacity( const int& newCapacity)
{
	assert(newCapacity>=0);
	T* newData = NULL;
	capacity_ = newCapacity;
	if(capacity_ == 0)
	{
		SAFE_DELETE_ARRAY(pData_);
		size_ = 0;
		return;
	}

	if(newCapacity >= size_)
	{
		newData = new T[newCapacity];
		assert(newData);
		memcpy_s(newData, newCapacity*sizeof(T), pData_, sizeof(T)*size_);
		SAFE_DELETE_ARRAY(pData_);
		pData_ = newData;
	}
	else if(newCapacity < size_)
	{
		newData = new T[newCapacity];
		assert(newData);
		memcpy_s(newData, newCapacity*sizeof(T), pData_, sizeof(T)*newCapacity);
		SAFE_DELETE_ARRAY(pData_);
		pData_ = newData;
	}
}

template<class T>
inline int Array<T>::Size( void ) const
{
	return size_;
}

template<class T>
void Array<T>::Append( const T& element)
{
	if(size_ == capacity_)
	{
		assert(capacity_<=INT_MAX/2); // make sure capacity * 2 won't overflow
		T* pNewData = new T[capacity_*2];
		memcpy_s(pNewData, capacity_*2*sizeof(T), pData_, capacity_*sizeof(T));
		capacity_*=2;
		delete[] pData_;
		pData_ = pNewData;
	}
	pData_[size_++] = element;
}

template<class T>
void Array<T>::Remove( const int& index )
{
	assert( index>=0 && index<size_ );
	int delIndex = 0;
	index <  0    ? delIndex = 0     : delIndex = index;
	index >= size_ ? delIndex = size_-1: delIndex = index;
	for(int i=delIndex; i<size_;)
	{
		pData_[i] = pData_[++i];
	}
	--size_;
	if(capacity_ - size_ > size_ && size_!=0 && capacity_ > DefaultCapacity) // Condition to shrink array
	{
		capacity_/=2;
		T* pOldData = pData_;
		pData_ = new T[capacity_];
		memcpy_s(pData_, capacity_*sizeof(T), pOldData, size_*sizeof(T));
		SAFE_DELETE(pOldData);
	}
}

template<class T>
void Array<T>::Clean( void )
{
	size_ = 0;
}

template<class T>
T* Array<T>::GetPtr( void )
{
	return pData_;
}

template<class T>
const T* Array<T>::GetPtr( void ) const
{
	return pData_;
}

template<class T>
void Array<T>::SetElement( const int& index, const T& element )
{
	this->operator[index] = element;
}

template<class T>
T Array<T>::GetElement( const int& index) const
{
	assert( index >= 0 && index < capacity_ )
	return *this[index];
}